package com.razorfish.configuration 
{
	import com.razorfish.configuration.entities.ConfigObjectType;
	import com.razorfish.configuration.entities.Group;
	import com.razorfish.configuration.entities.KeyTypePair;
	import com.razorfish.configuration.entities.PredefinedProperty;
	import com.razorfish.configuration.entities.Property;
	import com.razorfish.configuration.entities.SingleConfigObject;
	import flash.display.Stage;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.utils.Dictionary;
	/**
	 * ...
	 * @author derek
	 */
	
	public class ConfigService extends EventDispatcher
	{
		public static const ITEM_ID_PROP_NAME:String = "cid";
		public static const PROP_GROUP_NAME:String = "propertyGroup";
		public static const ITEM_GROUP_NAME:String = "itemGroup";
		public static const COND_NAME:String = "condition";
		
		private var _originalData:XML;
		private var _classDefDict:Dictionary;
		
		public function ConfigService()
		{
			
		}
		
		private static var _instance:ConfigService;
		public static function get instance():ConfigService
		{
			if (_instance == null)
			{
				_instance = new ConfigService();
			}
			return _instance;
		}
		
		public function init(stage:Stage = null):void
		{
			PredefinedProperty.init(stage);
		}
		
		public function loadFile(xmlPath:String):void
		{
			var loader:URLLoader = new URLLoader();
			loader.addEventListener(Event.COMPLETE, onDataComplete);
			loader.load(new URLRequest(xmlPath));
		}
		
		public function loadXML(xml:XML):void
		{
			parse(xml);
		}
		
		public function parse(rawData:XML):Boolean
		{
			_originalData = rawData;
			var propertyGroups:Vector.<Group> = new Vector.<Group>();
			var itemGroups:Vector.<Group> = new Vector.<Group>();
			
			var i:int = 0;
			for each (var propGroupXml:XML in _originalData[PROP_GROUP_NAME])
			{
				propertyGroups.push(new Group(propGroupXml, ConfigObjectType.PropertyGroup, i));
				i++;
			}
			
			i = 0;
			for each (var itemGroupXml:XML in _originalData[ITEM_GROUP_NAME])
			{
				itemGroups.push(new Group(itemGroupXml, ConfigObjectType.ItemGroup, i));
				i++;
			}
			
			// remove the groups that unmatch the condition
			var filterFunc:Function = function(item:Group, index:int, vector:Vector.<Group>):Boolean
			{
				if (!item.isAvailable)
				{
					for each (var obj:SingleConfigObject in item.children)
					{
						var type:String = obj is Property ? ConfigObjectType.Property : ConfigObjectType.Item;
						var arr:Array = SingleConfigObject.getSingleConfigObject(new KeyTypePair(obj.simpleName, type, 0));
						if (arr != null)
						{
							var objIndex:int = arr.indexOf(obj);
							if (objIndex > -1)
							{
								arr.splice(objIndex, 1);
							}
						}
					}
				}
				return item.isAvailable;
			};
			propertyGroups = propertyGroups.filter(filterFunc, null);
			itemGroups = itemGroups.filter(filterFunc, null);
			
			var objGetValueFunc:Function = function(item:SingleConfigObject, index:int, vector:Vector.<SingleConfigObject>):void 
			{
				item.tryGetValue();
			};
			
			var groupGetValueFunc:Function = function(item:Group, index:int, vector:Vector.<Group>):void 
			{
				item.children.forEach(objGetValueFunc, null);
			};
			
			var objCheckValueFunc:Function = function(item:SingleConfigObject, index:int, vector:Vector.<SingleConfigObject>):Boolean
			{
				return !item.isValueReady;
			}
			
			var groupCheckValueFunc:Function = function(item:Group, index:int, vector:Vector.<Group>):Boolean
			{
				return item.children.some(objCheckValueFunc, null);
			};
			
			while (propertyGroups.some(groupCheckValueFunc, null) && itemGroups.some(groupCheckValueFunc, null))
			{
				propertyGroups.forEach(groupGetValueFunc, null);
				itemGroups.forEach(groupGetValueFunc, null);
			}
			
			SingleConfigObject.dump();
			
			return true;
		}
		
		public function registerType(uniqueName:String, classDef:Class):void
		{
			if (!_classDefDict) _classDefDict = new Dictionary();
			_classDefDict[uniqueName] = classDef;
		}
		
		public function getType(uniqueName:String):Class 
		{
			if (!_classDefDict) return null;
			if (_classDefDict[uniqueName] == undefined) return null;
			else return _classDefDict[uniqueName] as Class;
		}
		
		public function getProperty(propName:String):String
		{
			return SingleConfigObject.getProperty(propName)[0].value;
		}
		
		public function getItem(objName:String):*
		{
			return SingleConfigObject.getItem(objName)[0].value;
		}
		
		private function onDataComplete(e:Event):void
		{
			var loader:URLLoader = e.target as URLLoader;
			if (loader != null)
			{
				var data:XML;
				try
				{
					data = new XML(loader.data);
				}
				catch (err:Error)
				{
					
				}
				
				if (data && parse(data))
				{
					dispatchEvent(e);
				}
			}
		}
		
		private function addListeners():void
		{
			
		}
		
		private function removeListeners():void
		{
			
		}
	}
}
